package com.example.im.xmpp

import com.example.im.bean.ChatBody
import com.example.im.bean.ChatEntry
import com.example.im.bean.ChatRecord
import com.example.im.bean.UserRoom
import com.example.im.common.Constants
import com.example.im.common.Enumerate
import com.example.im.db.DatabaseStorage
import com.example.im.bean.EventBusData
import com.example.im.utils.JsonUtils
import com.example.im.utils.LogUtils
import org.greenrobot.eventbus.EventBus
import org.jivesoftware.smack.SmackException
import org.jivesoftware.smack.XMPPConnection
import org.jivesoftware.smack.XMPPException
import org.jivesoftware.smack.chat2.Chat
import org.jivesoftware.smack.packet.Message
import org.jivesoftware.smack.packet.Presence
import org.jivesoftware.smack.packet.Stanza
import org.jivesoftware.smack.roster.RosterEntry
import org.jivesoftware.smack.roster.SubscribeListener
import org.jivesoftware.smack.roster.packet.RosterPacket
import org.jivesoftware.smackx.muc.MultiUserChat
import org.jivesoftware.smackx.muc.packet.MUCUser
import org.jxmpp.jid.EntityBareJid
import org.jxmpp.jid.EntityJid
import org.jxmpp.jid.Jid

import org.jivesoftware.smackx.iqregister.AccountManager
import org.jivesoftware.smackx.muc.RoomInfo
import org.jxmpp.jid.impl.JidCreate

open class DefaultConnection : DefaultConnectionListener {

    /**
     * 开始连接
     * */
    override fun connectedStart() {
        LogUtils.e("开始连接")
    }

    /**
     * 连接成功监听
     */
    override fun connected(connection: XMPPConnection) {
        LogUtils.e("连接成功")
    }

    /**
     * 认证成功监听即登录成功
     */
    override fun authenticated(connection: XMPPConnection, resumed: Boolean) {
        LogUtils.e("认证成功")
        val user = connection.user
        //创建数据库
        DatabaseStorage.initDatabaseCreate("${user.localpart.intern()}.db")
        //保存账号信息
        val mAccountManager = AccountManager.getInstance(connection)
        DatabaseStorage.setAccountInfoStorage(
            connection.user.asEntityBareJid().intern(),
            mAccountManager.getAccountAttribute("name"),
            mAccountManager.getAccountAttribute("username"),
            mAccountManager.getAccountAttribute("email")
        )
    }

    /**
     * 关闭连接监听
     */
    override fun connectionClosed() {
        LogUtils.e("连接关闭")
    }

    /**
     * 连接异常监听
     */
    override fun connectionClosedOnError(e: Exception) {
        LogUtils.e("连接错误" + e.toString() + ",," + e.cause)
        if (e is XMPPException.StreamErrorException) {
            //登录冲突
            if (e.streamError.toString()
                    .contains("urn:ietf:params:xml:ns:xmpp-streams")
            ) {
                IMConnection.instance?.disconnect()
                val supporter = EventBusData<Any>(
                    Enumerate.Handle.base_resource
                )
                EventBus.getDefault().post(supporter)
            }
        }
    }

    /**
     * IQ包监听
     */
    @Throws(
        SmackException.NotConnectedException::class,
        InterruptedException::class,
        SmackException.NotLoggedInException::class
    )
    override fun processStanza(packet: Stanza) {
        val from = packet.from
        val to = packet.to
        val sb = StringBuilder()
        if (packet is Presence) {
            when (packet.type) {
                Presence.Type.subscribe -> sb.append("请求订阅")
                Presence.Type.subscribed -> sb.append("同意订阅")
                Presence.Type.unsubscribe -> sb.append("取消订阅")
                Presence.Type.unsubscribed -> {
                    if (from != null) {
                        val userRoom = DatabaseStorage.getUserRoomStorageByAccount(
                            from.localpartOrThrow.intern()
                        ) ?: return
                        if (userRoom.sub == Constants.USER_ROOM_SUB_1) {
                            IMConnection.instance?.removeRosterEntries(userRoom.jid)
                            entriesDeleted(arrayListOf(JidCreate.from(userRoom.jid)))
                        }
                    }
                    sb.append("拒绝订阅")
                }
                Presence.Type.unavailable -> sb.append("离线")
                Presence.Type.available -> sb.append("上线")
                Presence.Type.error -> sb.append("error")
                else -> sb.append("probe")
            }
        }
        LogUtils.e(sb.append("，from：").append(from).append("，to：").append(to).toString())
    }

    override fun processSubscribe(jid: Jid, presence: Presence): SubscribeListener.SubscribeAnswer {
        return SubscribeListener.SubscribeAnswer.Approve
    }

    /**
     * 添加好友监听
     */
    override fun entriesAdded(addresses: Collection<Jid>) {
        updatedEntries2(addresses)
        LogUtils.e("CESHI-添加好友：${JsonUtils.objectToString(DatabaseStorage.getUserRoomToUser())}")
    }

    /**
     * 更新好友监听
     */
    override fun entriesUpdated(addresses: Collection<Jid>) {
        updatedEntries2(addresses)
        LogUtils.e("CESHI-更新好友：${JsonUtils.objectToString(DatabaseStorage.getUserRoomToUser())}")
    }

    /**
     * 订阅状态/更新好友操作
     * */
    private fun updatedEntries2(addresses: Collection<Jid>) {
        val imConnection = IMConnection.instance
            ?: return
        addresses.forEach {
            val entry = imConnection.getRosterEntries(it.intern())
                ?: return
            val userRoom1 = DatabaseStorage.getUserRoomStorageByAccount(
                it.localpartOrThrow.intern()
            )
            val userRoom2 = DatabaseStorage.setUserRoomStorage(entry)
                ?: return
            LogUtils.e(JsonUtils.objectToString(userRoom1))
            LogUtils.e(JsonUtils.objectToString(userRoom2))
            if (userRoom1 != null) {
                if (userRoom1.sub == Constants.USER_ROOM_SUB_1 && userRoom2.sub == Constants.USER_ROOM_SUB_3) {
                    //对方已同意添加您为好友
                    val chatBody = with(ChatBody(), {
                        this.type = Constants.CHAT_TYPE_OTHER
                        this.body = "对方已同意添加您为好友"
                        this.time = System.currentTimeMillis()
                        this.getChatBody()
                    })
                    this.preserveChatMessage(
                        userRoom2, chatBody, Constants.CHAT_KIND_1,
                        Constants.CHAT_ACTION_3, Constants.CHAT_STATUS_1
                    )
                } else if (userRoom1.sub == Constants.USER_ROOM_SUB_4 && userRoom2.sub == Constants.USER_ROOM_SUB_2) {
                    //说明之前添加过，则自动添加为好友
                    imConnection.setRosterCreate(userRoom2.jid, userRoom2.nickname)
                } else if (userRoom1.sub == Constants.USER_ROOM_SUB_1 && userRoom2.sub == Constants.USER_ROOM_SUB_0) {
                    //更新订阅关系为删除
                    DatabaseStorage.upUserRoomSub(Constants.USER_ROOM_SUB_4, userRoom2.id)
                } else if (userRoom1.sub == Constants.USER_ROOM_SUB_2 && userRoom2.sub == Constants.USER_ROOM_SUB_2) {
                    val eventBus = EventBusData(
                        Enumerate.Handle.list_subscribe, Enumerate.Action.list_delete, userRoom2
                    )
                    EventBus.getDefault().post(eventBus)
                }
            } else {
                if (userRoom2.sub == Constants.USER_ROOM_SUB_2 && userRoom2.nickname == null) {
                    val rows = IMConnection.instance?.getRosterSearch(userRoom2.account)
                        ?: return
                    userRoom2.nickname = rows[0].getValues("Name")[0].toString()
                    val eventBus = EventBusData(
                        Enumerate.Handle.list_subscribe, Enumerate.Action.list_add, userRoom2
                    )
                    EventBus.getDefault().post(eventBus)
                }
            }

        }
        val userRoomList2 = DatabaseStorage.getUserRoomToUser()
            ?: return
        val eventBus = EventBusData(
            Enumerate.Handle.list_friend, Enumerate.Action.list_add, userRoomList2
        )
        EventBus.getDefault().post(eventBus)
    }

    /**
     * 删除好友监听
     */
    override fun entriesDeleted(addresses: Collection<Jid>) {
        addresses.forEach {
            val userRoom =
                DatabaseStorage.getUserRoomStorageByAccount(it.localpartOrThrow.intern())
                    ?: return
            DatabaseStorage.deleteUserRoomStorage(userRoom)

            //通知聊天列表页面更新
            val eventBus1 = EventBusData(
                Enumerate.Handle.list_chat, Enumerate.Action.list_delete, userRoom
            )
            EventBus.getDefault().post(eventBus1)

            //通知更新好友列表
            val userRoomList2 = DatabaseStorage.getUserRoomToUser()
                ?: return
            val eventBus2 = EventBusData(
                Enumerate.Handle.list_friend, Enumerate.Action.list_add, userRoomList2
            )
            EventBus.getDefault().post(eventBus2)

            LogUtils.e("CESHI-删除好友：${it}")
        }
    }

    /**
     * 更改好友监听
     */
    override fun presenceChanged(presence: Presence) {
        LogUtils.e("更改好友：${presence.from}")
    }

    /**
     * 获取花名册信息监听
     * */
    override fun rosterEntries(rosterEntries: MutableCollection<RosterEntry>?) {
        val userRoomList1 = mutableListOf<UserRoom>()
        rosterEntries?.forEach {
            //保存用户信息
            val userRoom = DatabaseStorage.setUserRoomStorage(it)
                ?: return
            userRoomList1.add(userRoom)
            LogUtils.e("好友信息：${JsonUtils.objectToString(userRoom)}")
        }
        val userRoomMap = mutableMapOf<Int, UserRoom>()
        DatabaseStorage.getUserRoomToUserAll()?.forEach {
            userRoomMap[it.id] = it
        }
        userRoomList1.forEach {
            userRoomMap.remove(it.id)
        }
        userRoomMap.forEach {
            if (it.value.sub == Constants.USER_ROOM_SUB_3) {
                DatabaseStorage.upUserRoomSub(Constants.USER_ROOM_SUB_4, it.value.id)
            } else if (it.value.sub == Constants.USER_ROOM_SUB_1) {
                IMConnection.instance?.removeRosterEntries(it.value.jid)
                entriesDeleted(arrayListOf(JidCreate.from(it.value.jid)))
            }
        }
        val userRoomList2 = DatabaseStorage.getUserRoomToUser()
            ?: return
        //通知更新好友列表页面
        val eventBus = EventBusData(
            Enumerate.Handle.list_friend, Enumerate.Action.list_add, userRoomList2
        )
        EventBus.getDefault().post(eventBus)
    }

    /**
     * 获取书签聊天室监听
     */
    override fun onBookmarkedConferences(roomInfo: RoomInfo, sub: Int): UserRoom? {
        //保存聊天室信息
        val userRoom = DatabaseStorage.setUserRoomStorage(roomInfo, sub)
            ?: return null
        LogUtils.e("群聊信息：${JsonUtils.objectToString(userRoom)}")
        //通知更新聊天室列表页面
        val eventBus = EventBusData<UserRoom>(
            Enumerate.Handle.list_group, Enumerate.Action.list_add, userRoom
        )
        EventBus.getDefault().post(eventBus)
        return userRoom
    }

    /**
     * 请邀请监听
     */
    override fun invitationReceived(
        conn: XMPPConnection?,
        room: MultiUserChat?,
        inviter: EntityJid?,
        reason: String?,
        password: String?,
        message: Message?,
        invitation: MUCUser.Invite?
    ) {
        LogUtils.e("群聊邀请：")
        val imConnection = IMConnection.instance
            ?: return
        val roomInfo = imConnection.setConferenceJoin(
            imConnection.setConferenceBook(imConnection.getConferenceInfo(room!!.room.intern()))
        )
        val userRoom = this.onBookmarkedConferences(roomInfo, Constants.USER_ROOM_SUB_3)
            ?: DatabaseStorage.getUserRoomStorageByAccount(roomInfo.room.localpart.intern())
            ?: return

        val chatBody = with(ChatBody(), {
            this.type = Constants.CHAT_TYPE_OTHER
            this.body = "\"${inviter?.localpart?.intern()}\" 邀请您进入群聊"
            this.time = System.currentTimeMillis()
            this.getChatBody()
        })
        this.preserveChatMessage(
            userRoom, chatBody, Constants.CHAT_KIND_2,
            Constants.CHAT_ACTION_3, Constants.CHAT_STATUS_1
        )
    }

    /**
     * 被踢出群聊监听
     * @param roomId 群号
     * */
    override fun onOwnershipRevoked(roomInfo: RoomInfo) {
        LogUtils.e("你已被踢出群聊")
        val userRoom = onBookmarkedConferences(roomInfo, Constants.USER_ROOM_SUB_4)
            ?: return
        val chatBody = with(ChatBody(), {
            this.type = Constants.CHAT_TYPE_OTHER
            this.body = "您被群主移出群聊"
            this.time = System.currentTimeMillis()
            this.getChatBody()
        })
        this.preserveChatMessage(
            userRoom, chatBody, Constants.CHAT_KIND_2,
            Constants.CHAT_ACTION_3, Constants.CHAT_STATUS_1
        )
    }

    /**
     * 接收消息监听
     */
    override fun newIncomingMessage(
        entityBareJid: EntityBareJid,
        message: Message,
        chat: Chat
    ) {
        LogUtils.e("接收消息：${message.body}")

        val userRoom = DatabaseStorage.getUserRoomStorageByAccount(
            entityBareJid.localpart.intern()
        )
            ?: return
        this.preserveChatMessage(
            userRoom, message, Constants.CHAT_KIND_1,
            Constants.CHAT_ACTION_2, Constants.CHAT_STATUS_1
        )
    }

    /**
     * 发送消息监听
     */
    override fun newOutgoingMessage(
        entityBareJid: EntityBareJid,
        message: Message,
        chat: Chat
    ) {
        LogUtils.e("发送消息：${entityBareJid}，from = ${message.from}，to = ${message.to}")

        val userRoom = DatabaseStorage.getUserRoomStorageByAccount(
            entityBareJid.localpart.intern()
        )
            ?: return
        this.preserveChatMessage(
            userRoom, message, Constants.CHAT_KIND_1,
            Constants.CHAT_ACTION_1, Constants.CHAT_STATUS_0
        )
    }

    /**
     * 群聊消息监听
     */
    override fun processMessage(message: Message) {
        LogUtils.e("群聊信息：${message.body}，from = ${message.from.resourceOrNull.intern()}，to = ${message.to.intern()}")

        val userRoom = DatabaseStorage.getUserRoomStorageByAccount(
            message.from.localpartOrThrow.intern()
        )
            ?: return
        this.preserveChatMessage(
            userRoom, message,
            Constants.CHAT_KIND_2,
            if (message.from.resourceOrNull?.contains(
                    DatabaseStorage.getAccountInfoStorage().username ?: return
                ) ?: return
            ) Constants.CHAT_ACTION_1 else Constants.CHAT_ACTION_2,
            if (message.from.resourceOrNull?.contains(
                    DatabaseStorage.getAccountInfoStorage().username ?: return
                ) ?: return
            ) Constants.CHAT_STATUS_0 else Constants.CHAT_STATUS_1
        )
    }


    private fun preserveChatMessage(
        userRoom: UserRoom,
        message: Message?,
        body: ChatBody?,
        kind: Int,
        action: Int,
        status: Int
    ) {

        val chatBody = if (message != null) try {
            JsonUtils.stringToObject(
                message.body ?: return, ChatBody::class.java
            ) ?: return
        } catch (e: java.lang.Exception) {
            with(ChatBody(), {
                this.type = Constants.CHAT_TYPE_TEXT
                this.body = message.body
                this.time = System.currentTimeMillis()
                this.getChatBody()
            })
        } else body ?: return

        val from = if (action != Constants.CHAT_ACTION_3) {
            if (message != null)
                if (action == Constants.CHAT_ACTION_1)
                    DatabaseStorage.getAccountInfoStorage().jid
                else {
                    if (kind == Constants.CHAT_KIND_1)
                        message.from.asBareJid().intern()
                    else message.from.intern()
                }
            else if (kind == Constants.CHAT_KIND_1)
                DatabaseStorage.getAccountInfoStorage().jid
            else "${userRoom.jid}/${Constants.ROOM_NICKNAME}"
        } else null

        val to = if (action != Constants.CHAT_ACTION_3) {
            if (message == null)
                if (kind == Constants.CHAT_KIND_2)
                    DatabaseStorage.getAccountInfoStorage().jid else userRoom.jid
            else message.to.asBareJid().intern()
        } else null

        val chatRecord = DatabaseStorage.setChatRecordTime(userRoom.id, chatBody.time)
        if (chatRecord != null) {
            //通知
            val eventBus = EventBusData<ChatRecord>(
                Enumerate.Handle.list_chat, Enumerate.Action.list_add, chatRecord
            )
            EventBus.getDefault().post(eventBus)
        }

        if (action == Constants.CHAT_ACTION_2 && chatBody.type != Constants.CHAT_TYPE_TEXT) {
            chatBody.file?.localUrl = null
        }

        if (chatBody.type == Constants.CHAT_TYPE_CHANGE) {
            val roomInfo = IMConnection.instance?.getConferenceInfo(userRoom.jid)
                ?: return
            this.onBookmarkedConferences(roomInfo, Constants.USER_ROOM_SUB_3)
        }

        val chatLast = DatabaseStorage.setChatRecordStorage(
            userRoom, chatBody, from, to, kind, action, status
        ) ?: return

        val eventBus = EventBusData<ChatEntry>(
            Enumerate.Handle.list_chat, Enumerate.Action.list_add,
            DatabaseStorage.getChatEntryStorage(chatLast) ?: return
        )
        EventBus.getDefault().post(eventBus)
    }

    private fun preserveChatMessage(
        userRoom: UserRoom, message: Message, kind: Int, action: Int, status: Int
    ) {
        this.preserveChatMessage(userRoom, message, null, kind, action, status)
    }

    fun preserveChatMessage(
        userRoom: UserRoom, body: ChatBody, kind: Int, action: Int, status: Int
    ) {
        this.preserveChatMessage(userRoom, null, body, kind, action, status)
    }
}
